﻿using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace NMapper.Utils
{
    public class LambdaNullChecker 
    {
        public bool IsNestedProperty(Expression expression)
        {
            return expression is MemberExpression && ((MemberExpression)expression).Expression is MemberExpression;
        }

        public Expression AddNullCheckToParents(Expression expression, Expression ifNull)
        {
            var current = expression as MemberExpression;
            if (current != null)
                current = current.Expression as MemberExpression;
            var stack = new Stack<MemberExpression>();
            while (current != null)
            {
                stack.Push(current);
                current = current.Expression as MemberExpression;
            }
            var condition = (Expression)Expression.Constant(false);
            while (stack.Any())
            {
                var member = stack.Pop();
                condition = Expression.OrElse(condition, Expression.Equal(member, Expression.Convert(Expression.Constant(null), member.Type)));
            }
            return Expression.Condition(condition, ifNull, Expression.Convert(expression, ifNull.Type));
        }

        public Expression AddNullCheck(Expression expression, Expression ifNotNull) 
        {
            var current = expression;
            var stack = new Stack<Expression>();
            while (current != null)
            {
                if (current is MethodCallExpression)
                {
                    stack.Push(current);
                    var methodCallExpression = (MethodCallExpression)current;
                    current = methodCallExpression.Object as MemberExpression;
                }
                else if (current is MemberExpression)
                {
                    stack.Push(current);
                    var memberExpression = (MemberExpression)current;
                    current = memberExpression.Expression;
                }
                else
                {
                    current = null;
                }
            }
            var condition = (Expression)Expression.Constant(true);
            while (stack.Any())
            {
                var member = stack.Pop();
                condition = Expression.AndAlso(condition, Expression.NotEqual(member, Expression.Convert(Expression.Constant(null), member.Type)));
            }
            return Expression.Condition(condition, ifNotNull, Expression.Convert(Expression.Constant(null), ifNotNull.Type));
        }
    }
}